<!--
api 请求渲染组件，可指定 api 函数，快速生成 select、radio、checkbox 项，或者匹配渲染字段，api 请求的数据会自动缓存，短时间内不会重复请求，刷新页面会清除所有缓存
-->
<script setup lang="ts">
import { ApiRenderApiType } from '@/components/ApiRender/ApiRenderCache'
import { PropType } from 'vue'
import { useApiRender } from '@/components/ApiRender/useApiRender'

const props = defineProps({
  // 类型
  type: {
    type: String as PropType<'selectOptions' | 'radioItems' | 'checkboxItems' | 'text'>,
    default: 'text'
  },
  // 尽量使用有名函数，会自动垃圾回收，或者提供 apiKey，匿名函数是不安全的（可能重复）
  api: {
    type: Function as PropType<ApiRenderApiType>,
    required: true
  },
  // api 的 key 值，可用来声明 api 缓存的key，api 请求的数据会自动缓存，所以 api 函数尽量使用有名函数，或者如果使用匿名函数，在不保证匿名函数会字符会重复的前提下，请提供该字段
  apiKey: {
    type: [String, Number]
  },
  // 匹配的值
  value: {
    type: [String, Number, Boolean, Object] as PropType<any>
  },
  // value 关键字
  valueKey: {
    type: String,
    default: 'value'
  },
  // 显示名称的关键字
  labelKey: {
    type: String,
    default: 'label'
  },
  // 未匹配到时默认显示的名称，默认为''
  defaultLabel: {
    type: Function as PropType<any>,
    default: () => {
      let a = 0
      return ''
    }
  },
  /**
   * 远程搜索的参数名，默认会将该参数名作为搜索关键字
   */
  remoteParamKey: {
    type: String
  },
  /**
   * 远程搜索的参数，一个返回请求参数的方法，query 参数为输入的文字
   * <p>
   *   当指定该参数时，remoteParamKey 将失效
   * </p>
   */
  remoteParams: {
    type: Function as PropType<(query: string) => object>
  }
})

const { apiList, getApiItem, getItemByValue } = useApiRender()
const renderValue = ref<any>()

function exeApi() {
  getApiItem(props.api, props.valueKey, props.value, props.apiKey).then((res) => {
    if (res) {
      renderValue.value = res[props.labelKey]
    }
  })
}

exeApi()

watch(
  () => props.api,
  () => {
    exeApi()
  }
)

const remoteLoading = ref<boolean>(false)

function remoteMethod(query: string) {
  remoteLoading.value = true
  let params = {}
  if (props.remoteParams) {
    params = props.remoteParams(query)
  } else if (props.remoteParamKey) {
    params[props.remoteParamKey] = query
  }
  props
    .api(params)
    .then((res) => {
      apiList.value = res || []
      const item = getItemByValue(apiList.value, props.valueKey, props.value)
      if (item) {
        renderValue.value = item[props.labelKey]
      }
      remoteLoading.value = false
    })
    .catch(() => {
      remoteLoading.value = false
    })
}

/**
 * 根据值获取项
 */
function getItem(value: any) {
  return getItemByValue(apiList.value, props.valueKey, value)
}

defineExpose({ remoteMethod, loading: remoteLoading, getItem })
</script>

<template>
  <template v-if="props.type === 'selectOptions'">
    <el-option v-for="item in apiList" :key="item[props.valueKey]" :label="item[props.labelKey]" :value="item[props.valueKey]">
      <slot name="default" :item="item"></slot>
    </el-option>
  </template>
  <template v-else-if="props.type === 'radioItems'">
    <el-radio v-for="item in apiList" :key="item[props.valueKey]" :label="item[props.valueKey]">
      {{ item[props.labelKey] }}
    </el-radio>
  </template>
  <template v-else-if="props.type === 'checkboxItems'">
    <el-checkbox v-for="item in apiList" :key="item[props.valueKey]" :label="item[props.labelKey]" :value="item[props.valueKey]" />
  </template>
  <template v-else>{{ renderValue }}</template>
</template>

<style scoped lang="scss"></style>
